home *** CD-ROM | disk | FTP | other *** search
/ Internet Info 1994 March / Internet Info CD-ROM (Walnut Creek) (March 1994).iso / networking / ip / ka9q / net_src.arc / mbuf.c < prev    next >
Encoding:
C/C++ Source or Header  |  1989-05-08  |  8.7 KB  |  445 lines

  1. /* Primitive mbuf allocate/free routines */
  2.  
  3. #include "global.h"
  4. #include "mbuf.h"
  5.  
  6. /* Allocate mbuf with associated buffer of 'size' bytes */
  7. struct mbuf *
  8. alloc_mbuf(size)
  9. register int16 size;
  10. {
  11.     register struct mbuf *bp;
  12.  
  13.     if((bp = (struct mbuf *)malloc((unsigned)(size + sizeof(struct mbuf)))) == NULLBUF)
  14.         return NULLBUF;
  15.     bp->next = bp->anext = NULLBUF;
  16.     if(size != 0){
  17.         bp->data = (char *)(bp + 1);
  18.     } else {
  19.         bp->data = NULLCHAR;
  20.     }
  21.     bp->size = size;
  22.     bp->cnt = 0;
  23.     return bp;
  24. }
  25.  
  26. /* Free all resources associated with mbuf
  27.  * Return pointer to next mbuf in packet chain
  28.  */
  29. struct mbuf *
  30. free_mbuf(bp)
  31. register struct mbuf *bp;
  32. {
  33.     register struct mbuf *bp1 = NULLBUF;
  34.  
  35.     if(bp != NULLBUF){
  36.         bp1 = bp->next;
  37.         bp->next = NULLBUF;    /* detect attempts to use */
  38.         bp->data = NULLCHAR;    /* a freed mbuf */
  39.         free((char *)bp);
  40.     }
  41.     return bp1;
  42. }
  43.  
  44. /* Free packet (a chain of mbufs). Return pointer to next packet on queue,
  45.  * if any
  46.  */
  47. struct mbuf *
  48. free_p(bp)
  49. register struct mbuf *bp;
  50. {
  51.     struct mbuf *abp;
  52.  
  53.     if(bp == NULLBUF)
  54.         return NULLBUF;
  55.     abp = bp->anext;
  56.     while(bp != NULLBUF)
  57.         bp = free_mbuf(bp);
  58.     return abp;
  59. }        
  60. /* Free entire queue of packets (of mbufs) */
  61. free_q(q)
  62. struct mbuf **q;
  63. {
  64.     register struct mbuf *bp;
  65.  
  66.     while((bp = dequeue(q)) != NULLBUF)
  67.         free_p(bp);
  68. }
  69.  
  70. /* Count up the total number of bytes in an mbuf */
  71. int16
  72. len_mbuf(bp)
  73. register struct mbuf *bp;
  74. {
  75.     int cnt;
  76.  
  77.     cnt = 0;
  78.     while(bp != NULLBUF){
  79.         cnt += bp->cnt;
  80.         bp = bp->next;
  81.     }
  82.     return cnt;
  83. }
  84. /* Count up the number of packets in a queue */
  85. int16
  86. len_q(bp)
  87. register struct mbuf *bp;
  88. {
  89.     register int cnt;
  90.  
  91.     for(cnt=0;bp != NULLBUF;cnt++,bp = bp->anext)
  92.         ;
  93.     return cnt;
  94. }
  95. /* Trim mbuf to specified length by lopping off end */
  96. trim_mbuf(bpp,length)
  97. struct mbuf **bpp;
  98. int16 length;
  99. {
  100.     register int16 tot = 0;
  101.     register struct mbuf *bp;
  102.  
  103.     if(bpp == NULLBUFP || *bpp == NULLBUF)
  104.         return;    /* Nothing to trim */
  105.  
  106.     if(length == 0){
  107.         /* Toss the whole thing */
  108.         free_p(*bpp);
  109.         *bpp = NULLBUF;
  110.         return;
  111.     }
  112.     /* Find the point at which to trim. If length is greater than
  113.      * the packet, we'll just fall through without doing anything
  114.      */
  115.     for( bp = *bpp; bp != NULLBUF; bp = bp->next){
  116.         if(tot + bp->cnt < length){
  117.             tot += bp->cnt;
  118.         } else {
  119.             /* Cut here */
  120.             bp->cnt = length - tot;
  121.             free_p(bp->next);
  122.             bp->next = NULLBUF;
  123.             break;
  124.         }
  125.     }
  126. }
  127. /* Duplicate/enqueue/dequeue operations based on mbufs */
  128.  
  129. /* Duplicate first 'cnt' bytes of packet starting at 'offset'.
  130.  * This is done without copying data; only the headers are duplicated,
  131.  * but without data segments of their own. The pointers are set up to
  132.  * share the data segments of the original copy. The return pointer is
  133.  * passed back through the first argument, and the return value is the
  134.  * number of bytes actually duplicated.
  135.  */
  136. int16
  137. dup_p(hp,bp,offset,cnt)
  138. struct mbuf **hp;
  139. register struct mbuf *bp;
  140. register int16 offset;
  141. register int16 cnt;
  142. {
  143.     register struct mbuf *cp;
  144.     int16 tot;
  145.  
  146.     if(cnt == 0 || bp == NULLBUF || hp == NULLBUFP){
  147.         if(hp != NULLBUFP)
  148.             *hp = NULLBUF;
  149.         return 0;
  150.     }
  151.     if((*hp = cp = alloc_mbuf(0)) == NULLBUF){
  152.         return 0;
  153.     }
  154.     /* Skip over leading mbufs that are smaller than the offset */
  155.     while(bp != NULLBUF && bp->cnt <= offset){
  156.         offset -= bp->cnt;
  157.         bp = bp->next;
  158.     }
  159.     if(bp == NULLBUF){
  160.         free_mbuf(cp);
  161.         *hp = NULLBUF;
  162.         return 0;    /* Offset was too big */
  163.     }
  164.     tot = 0;
  165.     for(;;){
  166.         cp->data = bp->data + offset;
  167.         cp->cnt = min(cnt,bp->cnt - offset);
  168.         offset = 0;
  169.         cnt -= cp->cnt;
  170.         tot += cp->cnt;
  171.         bp = bp->next;
  172.         if(cnt == 0 || bp == NULLBUF || (cp->next = alloc_mbuf(0)) == NULLBUF)
  173.             break;
  174.         cp = cp->next;
  175.     }
  176.     return tot;
  177. }
  178. /* Copy first 'cnt' bytes of packet into a new, single mbuf */
  179. struct mbuf *
  180. copy_p(bp,cnt)
  181. register struct mbuf *bp;
  182. register int16 cnt;
  183. {
  184.     register struct mbuf *cp;
  185.     register char *wp;
  186.     register int16 n;
  187.  
  188.     if(bp == NULLBUF || cnt == 0 || (cp = alloc_mbuf(cnt)) == NULLBUF)
  189.         return NULLBUF;
  190.     wp = cp->data;
  191.     while(cnt != 0 && bp != NULLBUF){
  192.         n = min(cnt,bp->cnt);
  193.         memcpy(wp,bp->data,n);
  194.         wp += n;
  195.         cp->cnt += n;
  196.         cnt -= n;
  197.         bp = bp->next;
  198.     }
  199.     return cp;
  200. }
  201. /* Copy and delete "cnt" bytes from beginning of packet. Return number of
  202.  * bytes actually pulled off
  203.  */
  204. int16
  205. pullup(bph,buf,cnt)
  206. struct mbuf **bph;
  207. char *buf;
  208. int16 cnt;
  209. {
  210.     register struct mbuf *bp;
  211.     int16 n,tot;
  212.  
  213.     tot = 0;
  214.     if(bph == NULLBUFP)
  215.         return 0;
  216.     while(*bph != NULLBUF && cnt != 0){
  217.         bp = *bph;
  218.         n = min(cnt,bp->cnt);
  219.         if(buf != NULLCHAR && n != 0){
  220.             memcpy(buf,bp->data,n);
  221.             buf += n;
  222.         }
  223.         tot += n;
  224.         cnt -= n;
  225.         bp->data += n;
  226.         bp->cnt -= n;        
  227.         if(bp->cnt == 0){
  228.             *bph = free_mbuf(bp);
  229.         }
  230.     }
  231.     return tot;
  232. }
  233. /* Append mbuf to end of mbuf chain */
  234. void
  235. append(bph,bp)
  236. struct mbuf **bph;
  237. struct mbuf *bp;
  238. {
  239.     register struct mbuf *p;
  240.  
  241.     if(bph == NULLBUFP || bp == NULLBUF)
  242.         return;
  243.     if(*bph == NULLBUF){
  244.         /* First one on chain */
  245.         *bph = bp;
  246.     } else {
  247.         for(p = *bph ; p->next != NULLBUF ; p = p->next)
  248.             ;
  249.         p->next = bp;
  250.     }
  251. }
  252. /* Insert specified amount of contiguous new space at the beginning of an
  253.  * mbuf chain. If enough space is available in the first mbuf, no new space
  254.  * is allocated. Otherwise a mbuf of the appropriate size is allocated and
  255.  * tacked on the front of the chain.
  256.  *
  257.  * This operation is the logical inverse of pullup(), hence the name.
  258.  */
  259. struct mbuf *
  260. pushdown(bp,size)
  261. register struct mbuf *bp;
  262. int16 size;
  263. {
  264.     register struct mbuf *nbp;
  265.  
  266.     /* Check that bp is real and that there's data space associated with
  267.      * this buffer (i.e., this is not a buffer from dup_p) before
  268.      * checking to see if there's enough space at its front
  269.      */
  270.     if(bp != NULLBUF && bp->size != 0 && bp->data - (char *)(bp+1) >= size){
  271.         /* No need to alloc new mbuf, just adjust this one */
  272.         bp->data -= size;
  273.         bp->cnt += size;
  274.     } else {
  275.         if((nbp = alloc_mbuf(size)) != NULLBUF){
  276.             nbp->next = bp;
  277.             nbp->cnt = size;
  278.             bp = nbp;
  279.         } else {
  280.             bp = NULLBUF;
  281.         }
  282.     }
  283.     return bp;
  284. }
  285. /* Append packet to end of packet queue */
  286. void
  287. enqueue(q,bp)
  288. struct mbuf **q;
  289. struct mbuf *bp;
  290. {
  291.     register struct mbuf *p;
  292.     char i_state;
  293.  
  294.     if(q == NULLBUFP || bp == NULLBUF)
  295.         return;
  296.     i_state = disable();
  297.     if(*q == NULLBUF){
  298.         /* List is empty, stick at front */
  299.         *q = bp;
  300.     } else {
  301.         for(p = *q ; p->anext != NULLBUF ; p = p->anext)
  302.             ;
  303.         p->anext = bp;
  304.     }
  305.     restore(i_state);
  306. }
  307. /* Unlink a packet from the head of the queue */
  308. struct mbuf *
  309. dequeue(q)
  310. register struct mbuf **q;
  311. {
  312.     register struct mbuf *bp;
  313.     char i_state;
  314.  
  315.     if(q == NULLBUFP)
  316.         return NULLBUF;
  317.     i_state = disable();
  318.     if((bp = *q) != NULLBUF){
  319.         *q = bp->anext;
  320.         bp->anext = NULLBUF;
  321.     }
  322.     restore(i_state);
  323.     return bp;
  324. }    
  325.  
  326. /* Copy user data into an mbuf */
  327. struct mbuf *
  328. qdata(data,cnt)
  329. char *data;
  330. int16 cnt;
  331. {
  332.     register struct mbuf *bp;
  333.  
  334.     if((bp = alloc_mbuf(cnt)) == NULLBUF)
  335.         return NULLBUF;
  336.     memcpy(bp->data,data,cnt);
  337.     bp->cnt = cnt;
  338.     return bp;
  339. }
  340. /* Copy mbuf data into user buffer */
  341. int16
  342. dqdata(bp,buf,cnt)
  343. struct mbuf *bp;
  344. char *buf;
  345. unsigned cnt;
  346. {
  347.     unsigned n,tot;
  348.     struct mbuf *bp1;
  349.  
  350.     if(buf == NULLCHAR)
  351.         return 0;
  352.     
  353.     tot = 0;
  354.     for(bp1 = bp;bp1 != NULLBUF; bp1 = bp1->next){
  355.         n = min(bp1->cnt,cnt);
  356.         memcpy(buf,bp1->data,n);
  357.         cnt -= n;
  358.         buf += n;
  359.         tot += n;
  360.     }
  361.     free_p(bp);
  362.     return tot;
  363. }
  364. /* Pull a 32-bit integer in host order from buffer in network byte order */
  365. int32
  366. pull32(bpp)
  367. struct mbuf **bpp;
  368. {
  369.     int32 rval;
  370.     char buf[4];
  371.     register char *cp;
  372.  
  373.     if(pullup(bpp,buf,4) != 4){
  374.         /* Return zero if insufficient buffer */
  375.         return 0;
  376.     }
  377.     cp = buf;
  378.  
  379.     /* Unwound for speed */
  380.     rval = uchar(*cp++);
  381.     rval <<= 8;
  382.     rval |= uchar(*cp++);
  383.     rval <<= 8;
  384.     rval |= uchar(*cp++);
  385.     rval <<= 8;
  386.     rval |= uchar(*cp);
  387.  
  388.     return rval;
  389. }
  390. /* Pull a 16-bit integer in host order from buffer in network byte order */
  391. int16
  392. pull16(bpp)
  393. struct mbuf **bpp;
  394. {
  395.     int16 rval;
  396.     char buf[2];
  397.     register char *cp;
  398.  
  399.     if(pullup(bpp,buf,2) != 2){
  400.         /* Return zero if insufficient buffer */
  401.         return 0;
  402.     }
  403.     cp = buf;
  404.  
  405.     rval = uchar(*cp++);
  406.     rval <<= 8;
  407.     rval |= uchar(*cp);
  408.     return rval;
  409. }
  410. /* Pull single character from mbuf */
  411. char
  412. pullchar(bpp)
  413. struct mbuf **bpp;
  414. {
  415.     char c;
  416.  
  417.     if(pullup(bpp,&c,1) != 1)
  418.         /* Return zero if nothing left */
  419.         c = 0;
  420.     return c;
  421. }
  422. /* Put a long in host order into a char array in network order */
  423. char *
  424. put32(cp,x)
  425. register char *cp;
  426. int32 x;
  427. {
  428.     *cp++ = x >> 24;
  429.     *cp++ = x >> 16;
  430.     *cp++ = x >> 8;
  431.     *cp++ = x;
  432.     return cp;
  433. }
  434. /* Put a short in host order into a char array in network order */
  435. char *
  436. put16(cp,x)
  437. register char *cp;
  438. int16 x;
  439. {
  440.     *cp++ = x >> 8;
  441.     *cp++ = x;
  442.  
  443.     return cp;
  444. }
  445.